using System;
using System.Collections.Generic;
using System.Text;

namespace Lizk.SimpleHUD
{
    public class HUDVideo2 : HUDControl
    {
        public bool Closed { get; private set; }
        private int activeSubtitle = -1;
        private int activeAudiotrack = -1;
        private int activeAngle = -1;
        private int currentChapter;
        private int currentTitle;
        private int currentChannel;
        private string sourceUrl;
        private bool constrain = true;
        private SizeS sourceSize;
        private int chapterCount;
        private int titleCount;

        private TimeSpan duration;
        private TimeSpan position;
        private PlayerState state;
        private VideoUpdater updater;

        private List<TrackIdentifier> subtitles = new List<TrackIdentifier>();
        private List<TrackIdentifier> audiotracks = new List<TrackIdentifier>();
        private List<TrackIdentifier> angles = new List<TrackIdentifier>();
        private List<TrackIdentifier> channels = new List<TrackIdentifier>();

        public List<TrackIdentifier> Subtitles { get { return subtitles; } }
        public List<TrackIdentifier> Audiotracks { get { return audiotracks; } }
        public List<TrackIdentifier> Angles { get { return angles; } }
        public List<TrackIdentifier> Channels { get { return channels; } }

        public int TitleCount { get { return titleCount; } }
        public int ChapterCount { get { return chapterCount; } }

        public int CurrentTitle { get { return currentTitle; }
            set {
                if (value < 0 || value >= titleCount)
                    return;
                if (currentTitle != value)
                    updater.Command(VideoCommands.SetTitle, value);

            }
        }
        public int CurrentChapter
        {
            get { return currentChapter; }
            set {
                if (currentChapter != value)
                    updater.Command(VideoCommands.SetChapter, value);
            }
        }
        public int CurrentChannel
        {
            get { return currentChannel; }
            set
            {
                if (value < 0 || value >= channels.Count)
                    return;
                if (currentChannel != value)
                    updater.Command(VideoCommands.SetChannel, channels[value].id);
            }
        }

        public TimeSpan Duration { get { return duration; } }
        public TimeSpan Position { get { return position; } }
        public PlayerState State { get { return state; } }
        public VideoUpdater Updater { get { return updater; } }
        public string SourceUrl { get { return sourceUrl; } }
        public SizeS SourceSize { get { return sourceSize; }}
        public bool ConstrainProportions { get { return constrain; } set { constrain = value; } }
        public string ErrorMessage { get; set; }

        private ProcAmp procAmpCaps;

        public ProcAmp ProcAmpCaps
        {
            get { return procAmpCaps; }
        }

        public float Brightness
        {
            get { return brightness; }
            set
            {
                if ((procAmpCaps & ProcAmp.Brightness) == ProcAmp.Brightness && value != Brightness && value <= maxBrightness && value >= minBrightness)
                {
                    brightness = value;
                    updater.Command(VideoCommands.SetProcAmp, null);
                }
            }
        }

        public float Contrast
        {
            get { return contrast; }
            set
            {
                if ((procAmpCaps & ProcAmp.Contrast) == ProcAmp.Contrast && value != Contrast && value <= maxContrast && value >= minContrast)
                {
                    contrast = value;
                    updater.Command(VideoCommands.SetProcAmp, null);
                }
            }
        }
        public float Hue
        {
            get { return hue; }
            set
            {
                if ((procAmpCaps & ProcAmp.Hue) == ProcAmp.Hue && value != Hue && value <= maxHue && value >= minHue)
                {
                    hue = value;
                    updater.Command(VideoCommands.SetProcAmp, null);
                }
            }
        }
        public float Saturation
        {
            get { return saturation; }
            set
            {
                if ((procAmpCaps & ProcAmp.Saturation) == ProcAmp.Saturation && value != Saturation && value <= maxSaturation && value >= minSaturation)
                {
                    saturation = value;
                    updater.Command(VideoCommands.SetProcAmp, null);
                }
            }
        }

        protected float brightness, hue, contrast, saturation;
        protected float maxBrightness, minBrightness, stepBrightness;
        protected float maxHue, minHue, stepHue;
        protected float maxContrast, minContrast, stepContrast;
        protected float maxSaturation, minSaturation, stepSaturation;

        public float MaxBrightness { get { return maxBrightness; } }
        public float MinBrightness { get { return minBrightness; } }
        public float StepBrightness { get { return stepBrightness; } }
        public float MaxContrast { get { return maxContrast; } }
        public float MinContrast { get { return minContrast; } }
        public float StepContrast { get { return stepContrast; } }
        public float MaxSaturation { get { return maxSaturation; } }
        public float MinSaturation { get { return minSaturation; } }
        public float StepSaturation { get { return stepSaturation; } }
        public float MaxHue { get { return maxHue; } }
        public float MinHue { get { return minHue; } }
        public float StepHue { get { return stepHue; } }




        public int ActiveSubtitle
        {
            get { return activeSubtitle; }
            set
            {
                if (value < 0 || value >= subtitles.Count)
                    return;
                if(activeSubtitle != value)
                    updater.Command(VideoCommands.ChangeSubtitle, subtitles[value].id);
            }
        }

        public int ActiveAudiotrack
        {
            get { return activeAudiotrack; }
            set
            {
                if (value < 0 || value >= audiotracks.Count)
                    return;
                if (activeAudiotrack != value)
                    updater.Command(VideoCommands.ChangeAudioTrack, audiotracks[value].id);
            }
        }

        public int ActiveAngle
        {
            get { return activeAngle; }
            set
            {
                if (value < 0 || value >= angles.Count)
                    return;

                if (activeAngle != value)
                    updater.Command(VideoCommands.ChangeAngle, angles[value].id);

            }

        }

        public event EventHandler TrackAmountChange;
        public event EventHandler TrackChange;
        public event EventHandler StateChange;

        public HUDVideo2(string sourceUrl)
        {
            updater = new VideoUpdater(this);
            this.sourceUrl = sourceUrl;
        }

        public void Load()
        {
            updater.Command(VideoCommands.Load, null);
        }

        public void Play()
        {
            updater.Command(VideoCommands.Play, null);
        }

        public void Pause()
        {
            updater.Command(VideoCommands.Pause, null);
        }

        public void Stop()
        {
            updater.Command(VideoCommands.Stop, null);
        }

        public void Close()
        {
            Closed = true;
            updater.Command(VideoCommands.Stop, null);
        }

        public void Seek(TimeSpan ts, bool absolute)
        {
            updater.Command(VideoCommands.Seek, new object[] { ts, absolute });
        }

        public void RootMenu()
        {
            updater.Command(VideoCommands.RootMenu, null);
        }

        public void TitleMenu()
        {
            updater.Command(VideoCommands.TitleMenu, null);
        }

        public void MenuMoveUp()
        {
            updater.Command(VideoCommands.MenuUp, null);
        }

        public void MenuMoveDown()
        {
            updater.Command(VideoCommands.MenuDown, null);
        }

        public void MenuMoveLeft()
        {
            updater.Command(VideoCommands.MenuLeft, null);
        }

        public void MenuMoveRight()
        {
            updater.Command(VideoCommands.MenuRight, null);
        }

        public void MenuSelect()
        {
            updater.Command(VideoCommands.MenuSelect, null);
        }


        public class VideoUpdater
        {
            private HUDVideo2 video;
            internal VideoUpdater(HUDVideo2 video)
            {
                this.video = video;
            }

            private Queue<KeyValuePair<VideoCommands, object[]>> pendingCommands = new Queue<KeyValuePair<VideoCommands, object[]>>();
            public Queue<KeyValuePair<VideoCommands, object[]>> PendingCommands { get { return pendingCommands; } }

            internal void Command(VideoCommands command, params object[] parameters) 
            {
                pendingCommands.Enqueue(new KeyValuePair<VideoCommands, object[]>(command, parameters));
            }

            public void SetState(PlayerState state)
            {
                video.state = state;
                if (video.StateChange != null)
                {
                    video.StateChange(video, EventArgs.Empty);
                }
            }

            public void SetPosition(TimeSpan position)
            {
                video.position = position;
            }
            public void SetDuration(TimeSpan duration)
            {
                video.duration = duration;
            }

            public void SetAudiotracks(IEnumerable<TrackIdentifier> tracks)
            {
                video.audiotracks = new List<TrackIdentifier>(tracks);
                if (video.TrackAmountChange != null)
                    video.TrackAmountChange(video, EventArgs.Empty);
            }

            public void SetSubtitles(IEnumerable<TrackIdentifier> tracks)
            {
                video.subtitles = new List<TrackIdentifier>(tracks);
                if (video.TrackAmountChange != null)
                    video.TrackAmountChange(video, EventArgs.Empty);
            }
            
            public void SetChannels(IEnumerable<TrackIdentifier> tracks)
            {
                video.channels = new List<TrackIdentifier>(tracks);
                if (video.TrackAmountChange != null)
                    video.TrackAmountChange(video, EventArgs.Empty);
            }

            public void SetAngles(IEnumerable<TrackIdentifier> angles)
            {
                video.angles = new List<TrackIdentifier>(angles);
                if (video.TrackAmountChange != null)
                    video.TrackAmountChange(video, EventArgs.Empty);
            }

            public void SetActiveAudiotrack(int id)
            {
                for (int i = 0; i < video.audiotracks.Count; i++)
                {
                    if (video.audiotracks[i].id == id)
                        video.activeAudiotrack = i;
                }
                if (video.TrackChange != null)
                    video.TrackChange(video, EventArgs.Empty); 
            }

            public void SetActiveSubtitle(int id)
            {
                for (int i = 0; i < video.subtitles.Count; i++)
                {
                    if (video.subtitles[i].id == id)
                        video.activeSubtitle = i;
                }

                if (video.TrackChange != null)
                    video.TrackChange(video, EventArgs.Empty); 
            }

            public void SetActiveAngle(int id)
            {
                video.activeAngle = id;
                if (video.TrackChange != null)
                    video.TrackChange(video, EventArgs.Empty);
            }

            public void SetCurrentChapter(int id)
            {
                video.currentChapter = id;
            }
            public void SetCurrentTitle(int id)
            {
                video.currentTitle = id;
            }
            public void SetCurrentChannel(int id)
            {
                for (int i = 0; i < video.channels.Count; i++)
                {
                    if (video.channels[i].id == id)
                        video.currentChannel = i;
                }
                if (video.TrackChange != null)
                    video.TrackChange(video, EventArgs.Empty);
            }
            public void SetChapterCount(int id)
            {
                video.chapterCount = id;
            }
            public void SetTitleCount(int id)
            {
                video.titleCount = id;
            }
            public void SetSourceSize(SizeS size)
            {
                video.sourceSize = size ;
            }

            public void SetProcAmp(ProcAmp procAmpCaps, float Brightness, float stepBrightness, float maxBrightness, float minBrightness, float Contrast, float stepContrast, float maxContrast, float minContrast, float Saturation, float stepSaturation, float maxSaturation, float minSaturation, float Hue, float stepHue, float maxHue, float minHue)
            {
                video.procAmpCaps = procAmpCaps;
                video.brightness = Brightness;
                video.stepBrightness = stepBrightness;
                video.minBrightness = minBrightness;
                video.maxBrightness = maxBrightness;
                video.contrast = Contrast;
                video.stepContrast = stepContrast;
                video.minContrast = minContrast;
                video.maxContrast = maxContrast;
                video.saturation = Saturation;
                video.stepSaturation = stepSaturation;
                video.minSaturation = minSaturation;
                video.maxSaturation = maxSaturation;
                video.hue = Hue;
                video.stepHue = stepHue;
                video.minHue = minHue;
                video.maxHue = maxHue;
            }
        }


        public struct TrackIdentifier
        {
            public string name;
            public int id;
        }

        public enum PlayerState
        {
            NotLoaded,
            Stopped,
            Playing,
            Paused,
            Menu,
            Error
        }

        
        public enum VideoCommands
        {
            Load,
            Play,
            Pause,
            Stop,
            Seek,
            ChangeSubtitle,
            ChangeAudioTrack,
            ChangeAngle,
            RootMenu,
            TitleMenu,
            SetTitle,
            SetChapter,
            SetChannel,
            MenuUp,
            MenuDown,
            MenuLeft,
            MenuRight,
            MenuSelect,
            MenuMouseHover,
            SetProcAmp
        }

        [Flags]
        public enum ProcAmp { Brightness = 1, Contrast = 2, Saturation = 4, Hue = 8, None = 0 } 

    }   
}
